package com.reactim.message.metrics;

import io.micrometer.core.instrument.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 连接管理性能监控指标
 */
@Slf4j
@Component
public class ConnectionPerformanceMetrics {
    
    private final MeterRegistry meterRegistry;
    
    // 连接操作计时器
    private final Timer connectionStoreTimer;
    private final Timer connectionRetrieveTimer;
    private final Timer connectionRemoveTimer;
    private final Timer onlineCheckTimer;
    private final Timer onlineCountTimer;
    
    // 连接操作计数器
    private final Counter connectionStoreCounter;
    private final Counter connectionRetrieveCounter;
    private final Counter connectionRemoveCounter;
    private final Counter connectionStoreErrorCounter;
    private final Counter connectionRetrieveErrorCounter;
    
    // 连接状态统计
    private final AtomicLong currentConnections = new AtomicLong(0);
    private final AtomicLong totalConnectionsCreated = new AtomicLong(0);
    private final AtomicLong totalConnectionsRemoved = new AtomicLong(0);
    
    // 性能统计
    private final LongAdder totalStoreOperations = new LongAdder();
    private final LongAdder totalRetrieveOperations = new LongAdder();
    private final LongAdder totalRemoveOperations = new LongAdder();
    
    // 延迟统计
    private final DistributionSummary storeLatencyDistribution;
    private final DistributionSummary retrieveLatencyDistribution;
    
    public ConnectionPerformanceMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 初始化计时器
        this.connectionStoreTimer = Timer.builder("connection.store.time")
                .description("连接存储操作耗时")
                .register(meterRegistry);
        
        this.connectionRetrieveTimer = Timer.builder("connection.retrieve.time")
                .description("连接检索操作耗时")
                .register(meterRegistry);
        
        this.connectionRemoveTimer = Timer.builder("connection.remove.time")
                .description("连接移除操作耗时")
                .register(meterRegistry);
        
        this.onlineCheckTimer = Timer.builder("connection.online_check.time")
                .description("在线状态检查耗时")
                .register(meterRegistry);
        
        this.onlineCountTimer = Timer.builder("connection.online_count.time")
                .description("在线用户统计耗时")
                .register(meterRegistry);
        
        // 初始化计数器
        this.connectionStoreCounter = Counter.builder("connection.store.count")
                .description("连接存储操作次数")
                .register(meterRegistry);
        
        this.connectionRetrieveCounter = Counter.builder("connection.retrieve.count")
                .description("连接检索操作次数")
                .register(meterRegistry);
        
        this.connectionRemoveCounter = Counter.builder("connection.remove.count")
                .description("连接移除操作次数")
                .register(meterRegistry);
        
        this.connectionStoreErrorCounter = Counter.builder("connection.store.errors")
                .description("连接存储错误次数")
                .register(meterRegistry);
        
        this.connectionRetrieveErrorCounter = Counter.builder("connection.retrieve.errors")
                .description("连接检索错误次数")
                .register(meterRegistry);
        
        // 初始化延迟分布统计
        this.storeLatencyDistribution = DistributionSummary.builder("connection.store.latency")
                .description("连接存储操作延迟分布")
                .baseUnit("milliseconds")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(meterRegistry);
        
        this.retrieveLatencyDistribution = DistributionSummary.builder("connection.retrieve.latency")
                .description("连接检索操作延迟分布")
                .baseUnit("milliseconds")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(meterRegistry);
        
        // 注册自定义指标
        Gauge.builder("connection.current.count", this, ConnectionPerformanceMetrics::getCurrentConnections)
                .description("当前连接数")
                .register(meterRegistry);
        
        Gauge.builder("connection.total.created", this, ConnectionPerformanceMetrics::getTotalConnectionsCreated)
                .description("总创建连接数")
                .register(meterRegistry);
        
        Gauge.builder("connection.total.removed", this, ConnectionPerformanceMetrics::getTotalConnectionsRemoved)
                .description("总移除连接数")
                .register(meterRegistry);
        
        Gauge.builder("connection.operations.store.rate", this, ConnectionPerformanceMetrics::getStoreOperationRate)
                .description("连接存储操作速率")
                .register(meterRegistry);
        
        Gauge.builder("connection.operations.retrieve.rate", this, ConnectionPerformanceMetrics::getRetrieveOperationRate)
                .description("连接检索操作速率")
                .register(meterRegistry);
    }
    
    /**
     * 记录连接存储操作
     */
    public <T> T recordStoreOperation(java.util.function.Supplier<T> operation) {
        try {
            return connectionStoreTimer.recordCallable(() -> {
                connectionStoreCounter.increment();
                totalStoreOperations.increment();
                
                long startTime = System.nanoTime();
                try {
                    T result = operation.get();
                    long duration = System.nanoTime() - startTime;
                    storeLatencyDistribution.record(duration / 1_000_000.0); // 转换为毫秒
                    
                    // 假设操作成功，增加当前连接数
                    currentConnections.incrementAndGet();
                    totalConnectionsCreated.incrementAndGet();
                    
                    return result;
                } catch (Exception e) {
                    connectionStoreErrorCounter.increment();
                    log.error("连接存储操作失败", e);
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录连接检索操作
     */
    public <T> T recordRetrieveOperation(java.util.function.Supplier<T> operation) {
        try {
            return connectionRetrieveTimer.recordCallable(() -> {
                connectionRetrieveCounter.increment();
                totalRetrieveOperations.increment();
                
                long startTime = System.nanoTime();
                try {
                    T result = operation.get();
                    long duration = System.nanoTime() - startTime;
                    retrieveLatencyDistribution.record(duration / 1_000_000.0); // 转换为毫秒
                    return result;
                } catch (Exception e) {
                    connectionRetrieveErrorCounter.increment();
                    log.error("连接检索操作失败", e);
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录连接移除操作
     */
    public <T> T recordRemoveOperation(java.util.function.Supplier<T> operation) {
        try {
            return connectionRemoveTimer.recordCallable(() -> {
                connectionRemoveCounter.increment();
                totalRemoveOperations.increment();
                
                try {
                    T result = operation.get();
                    
                    // 假设操作成功，减少当前连接数
                    currentConnections.decrementAndGet();
                    totalConnectionsRemoved.incrementAndGet();
                    
                    return result;
                } catch (Exception e) {
                    log.error("连接移除操作失败", e);
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录在线状态检查操作
     */
    public <T> T recordOnlineCheckOperation(java.util.function.Supplier<T> operation) {
        try {
            return onlineCheckTimer.recordCallable(operation::get);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录在线用户统计操作
     */
    public <T> T recordOnlineCountOperation(java.util.function.Supplier<T> operation) {
        try {
            return onlineCountTimer.recordCallable(operation::get);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 获取当前连接数
     */
    public long getCurrentConnections() {
        return currentConnections.get();
    }
    
    /**
     * 获取总创建连接数
     */
    public long getTotalConnectionsCreated() {
        return totalConnectionsCreated.get();
    }
    
    /**
     * 获取总移除连接数
     */
    public long getTotalConnectionsRemoved() {
        return totalConnectionsRemoved.get();
    }
    
    /**
     * 获取存储操作速率
     */
    public double getStoreOperationRate() {
        return connectionStoreCounter.count();
    }
    
    /**
     * 获取检索操作速率
     */
    public double getRetrieveOperationRate() {
        return connectionRetrieveCounter.count();
    }
    
    /**
     * 获取性能统计报告
     */
    public PerformanceReport getPerformanceReport() {
        return PerformanceReport.builder()
                .currentConnections(currentConnections.get())
                .totalConnectionsCreated(totalConnectionsCreated.get())
                .totalConnectionsRemoved(totalConnectionsRemoved.get())
                .totalStoreOperations(totalStoreOperations.sum())
                .totalRetrieveOperations(totalRetrieveOperations.sum())
                .totalRemoveOperations(totalRemoveOperations.sum())
                .storeOperationCount(connectionStoreCounter.count())
                .retrieveOperationCount(connectionRetrieveCounter.count())
                .removeOperationCount(connectionRemoveCounter.count())
                .storeErrorCount(connectionStoreErrorCounter.count())
                .retrieveErrorCount(connectionRetrieveErrorCounter.count())
                .averageStoreTime(connectionStoreTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageRetrieveTime(connectionRetrieveTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageRemoveTime(connectionRemoveTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageOnlineCheckTime(onlineCheckTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageOnlineCountTime(onlineCountTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .storeLatencyP50(getPercentileValue(storeLatencyDistribution, 0.5))
                .storeLatencyP95(getPercentileValue(storeLatencyDistribution, 0.95))
                .storeLatencyP99(getPercentileValue(storeLatencyDistribution, 0.99))
                .retrieveLatencyP50(getPercentileValue(retrieveLatencyDistribution, 0.5))
                .retrieveLatencyP95(getPercentileValue(retrieveLatencyDistribution, 0.95))
                .retrieveLatencyP99(getPercentileValue(retrieveLatencyDistribution, 0.99))
                .build();
    }
    
    /**
     * 获取百分位数值
     */
    private double getPercentileValue(DistributionSummary distributionSummary, double percentile) {
        try {
            // 尝试使用新版本的API
            return distributionSummary.takeSnapshot().percentileValues()[0].value();
        } catch (Exception e) {
            // 如果新API不可用，返回默认值
            log.debug("无法获取百分位数值，返回默认值0.0");
            return 0.0;
        }
    }
    
    /**
     * 重置统计数据
     */
    public void reset() {
        currentConnections.set(0);
        totalConnectionsCreated.set(0);
        totalConnectionsRemoved.set(0);
        totalStoreOperations.reset();
        totalRetrieveOperations.reset();
        totalRemoveOperations.reset();
        log.info("连接性能监控统计数据已重置");
    }
    
    /**
     * 性能报告数据结构
     */
    @lombok.Data
    @lombok.Builder
    public static class PerformanceReport {
        private long currentConnections;
        private long totalConnectionsCreated;
        private long totalConnectionsRemoved;
        private long totalStoreOperations;
        private long totalRetrieveOperations;
        private long totalRemoveOperations;
        private double storeOperationCount;
        private double retrieveOperationCount;
        private double removeOperationCount;
        private double storeErrorCount;
        private double retrieveErrorCount;
        private double averageStoreTime;
        private double averageRetrieveTime;
        private double averageRemoveTime;
        private double averageOnlineCheckTime;
        private double averageOnlineCountTime;
        private double storeLatencyP50;
        private double storeLatencyP95;
        private double storeLatencyP99;
        private double retrieveLatencyP50;
        private double retrieveLatencyP95;
        private double retrieveLatencyP99;
        
        @Override
        public String toString() {
            return String.format(
                "ConnectionPerformanceReport{\n" +
                "  当前连接数: %d\n" +
                "  总创建连接数: %d\n" +
                "  总移除连接数: %d\n" +
                "  存储操作次数: %.0f (错误: %.0f)\n" +
                "  检索操作次数: %.0f (错误: %.0f)\n" +
                "  移除操作次数: %.0f\n" +
                "  平均存储耗时: %.2f ms\n" +
                "  平均检索耗时: %.2f ms\n" +
                "  平均移除耗时: %.2f ms\n" +
                "  平均在线检查耗时: %.2f ms\n" +
                "  平均在线统计耗时: %.2f ms\n" +
                "  存储延迟分布: P50=%.2fms, P95=%.2fms, P99=%.2fms\n" +
                "  检索延迟分布: P50=%.2fms, P95=%.2fms, P99=%.2fms\n" +
                "}",
                currentConnections, totalConnectionsCreated, totalConnectionsRemoved,
                storeOperationCount, storeErrorCount,
                retrieveOperationCount, retrieveErrorCount,
                removeOperationCount,
                averageStoreTime, averageRetrieveTime, averageRemoveTime,
                averageOnlineCheckTime, averageOnlineCountTime,
                storeLatencyP50, storeLatencyP95, storeLatencyP99,
                retrieveLatencyP50, retrieveLatencyP95, retrieveLatencyP99
            );
        }
    }
}